//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.imu.security;

import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Base64;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import com.alibaba.fastjson.JSON;
import com.imu.common.exception.ErrorDesc;
import com.imu.common.exception.RRException;
import com.imu.common.utils.SpringContextUtils;
import com.imu.common.validator.Assert;
import com.imu.constant.Constant;
import com.imu.utils.ShortUUID;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.util.CollectionUtil;
import com.xiaoleilu.hutool.util.StrUtil;

public class SessionTokenProviderRedis extends SessionTokenProviderAbstract 
{
    protected static int expiresInSeconds = 1800;
    private static SessionTokenProviderRedis me;

    private static ISessionTokenProvider initialize() 
    {
        if(me == null) 
        {
            me = new SessionTokenProviderRedis();
        }
        
        return me;
    }

    public static ISessionTokenProvider getSessionTokenProvider() 
    {
        return initialize();
    }

    public static void destroySessionTokenProvider() 
    {
        me = null;
    }

    public SessionTokenProviderRedis()
    {
        this.setTimeout((long)expiresInSeconds);
    }

    public void setTimeout(long timeoutInMilliseconds)
    {
        expiresInSeconds = (int)(timeoutInMilliseconds / 1000L);
    }

    public SessionObject setSession(String id, String term ,String username, String sex, boolean mobile)
    {
    	Assert.isBlank(id,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        String token = this.getBaasBoxTokenFromRedisKey(id + ":" + ShortUUID.UUID());
        long now = (new Date()).getTime();
        String secret = SecureUtil.md5(id + (mobile ? Constant.MOBILE : Constant.PC));
        
        SessionObject info = SessionObject.create(token, id, username, sex, secret, term, now, now + (long)(expiresInSeconds * 1000));
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        operations.set(getUserTokenKey(secret, token), JSON.toJSONString(info), Constant.SESSION_TIMEOUT, TimeUnit.SECONDS);
        return info;
    }

    public static String getUserTokenKey(String secret, String token)
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        return Constant.SESSION_FIX + secret + ":" + token;
    }

    public SessionObject updateSession(String secret, String token, SessionObject info) 
    {
    	Assert.isBlank(info,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(token, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
        long now = (new Date()).getTime();
        info.setStartTime(now);
        info.setExpirationTime(now + (long)(expiresInSeconds * 1000));
        redisTemplate.opsForValue().set(getUserTokenKey(secret, token), JSON.toJSONString(info), Constant.SESSION_TIMEOUT, TimeUnit.SECONDS);
        return info;
    }

    public SessionObject getSession(String secret, String token) 
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
    	ValueOperations<String, String> operations = redisTemplate.opsForValue();
    	String session = operations.get(getUserTokenKey(secret, token));
    	if(StrUtil.isBlank(session)) return null;
    	
    	return JSON.parseObject(session, SessionObject.class);
    }
    
    public void removeSession(String secret)
    {
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Set<String> keys = redisTemplate.keys(Constant.SESSION_FIX + secret + ":*");
    	if(CollectionUtil.isNotEmpty(keys))
    	{
    		redisTemplate.delete(keys);
    	}
    }

    public void removeSession(String secret, String token) 
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	redisTemplate.delete(getUserTokenKey(secret, token));
    }
    
    public SessionObject getCurrent(String secret, String token) 
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
    	ValueOperations<String, String> operations = redisTemplate.opsForValue();
    	String session = operations.get(getUserTokenKey(secret, token));
    	
    	if(StrUtil.isBlank(session)) return null;
    	return JSON.parseObject(session, SessionObject.class);
    }
    
    public String getUserId(String secret, String token)
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
        
    	SessionObject session = getCurrent(secret, token);
    	if(null == session || StrUtil.isBlank(session.getId()))
        {
        	throw new RRException(ErrorDesc.SESSION_EMPTY.getMsg(), ErrorDesc.SESSION_EMPTY.getCode());
        }
        
    	return session.getId();
    }
    
    private String getBaasBoxTokenFromRedisKey(String redisToken) 
    {
        return new String(Base64.encodeBase64(redisToken.toString().getBytes()));
    }
    
    @Override
	public Enumeration<String> getTokens()
    {
		// TODO Auto-generated method stub
		return null;
	}
    
    public List<SessionObject> getSessions(String username) 
    {
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	private final RedisTemplate<String, String> redisTemplate = SpringContextUtils.getBean("redisTemplate", RedisTemplate.class);
}
